/*
 * CastDRAndroid
 * Copyright (c) 2014 Christian Holm Christensen
 *
 * This program is free software: you can redistribute it and/or modify it
 * under the terms of the GNU General Public License as published by the Free
 * Software Foundation, either version 3 of the License, or (at your option)
 * any later version.
 *
 * This program is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
 * FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License along with
 * this program.  If not, see <http://www.gnu.org/licenses/>.
 */

package org.cholm.media.castdr;

import android.annotation.TargetApi;
import android.app.AlertDialog;
import android.content.Context;
import android.content.DialogInterface;
import android.content.SharedPreferences;
import android.content.res.Configuration;
import android.os.Build;
import android.os.Bundle;
import android.preference.EditTextPreference;
import android.preference.ListPreference;
import android.preference.Preference;
import android.preference.PreferenceActivity;
import android.preference.PreferenceFragment;
import android.preference.PreferenceManager;
import android.support.v4.app.NavUtils;
import android.support.v7.app.ActionBarPreferenceActivity;
import android.view.MenuItem;

import com.google.sample.castcompanionlibrary.cast.VideoCastManager;

import java.util.List;
import java.util.Map;

import static org.cholm.media.castdr.LogUtils.LOGd;
import static org.cholm.media.castdr.LogUtils.LOGw;

/**
 * A {@link PreferenceActivity} that presents a set of application settings. On
 * handset devices, settings are presented as a single list. On tablets,
 * settings are split by category, with category headers shown to the left of
 * the list of settings.
 * <p/>
 * See <a href="http://developer.android.com/design/patterns/settings.html">
 * Android Design: Settings</a> for design guidelines and the <a
 * href="http://developer.android.com/guide/topics/ui/settings.html">Settings
 * API Guide</a> for more information on developing a Settings UI.
 */
public class Settings extends ActionBarPreferenceActivity {
    private static final String TAG = LogUtils.makeLogTag(Settings.class);
    private static final String APPLICATION_ID = "ACA070E7";
    private static final String TERM_POLICY_KEY = "termination_policy";
    private static final String APP_ID_KEY = "cast_app_id";
    private static final String BIT_RATE_KEY = "pref_bit_rate";
    private static final String VOL_CTRL_KEY = "pref_volume_ctrl";
    /**
     * Determines whether to always show the simplified settings UI, where
     * settings are presented in a single list. When false, settings are shown
     * as a master/detail two-pane view on tablets. When true, a single pane is
     * shown on tablets.
     */
    private static final boolean ALWAYS_SIMPLE_PREFS = false;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setupActionBar();
        PreferenceManager.setDefaultValues(this, R.xml.pref_general, true);
        SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences
                (this);
        Map<String, ?> m = sp.getAll();
        for (String key : m.keySet()) {
            Object o = m.get(key);
            LOGd(TAG, "Preference " + key + " " + o);
        }
        // LOGd(TAG, "Setting defaults as needed");
        // PreferenceManager.setDefaultValues(this, R.xml.pref_general, false);
    }

    /**
     * Get the application ID preference
     *
     * @param ctx Context
     * @return The application ID
     */
    public static String getApplicationId(Context ctx) {
        SharedPreferences sharedPref = PreferenceManager.getDefaultSharedPreferences(ctx);
        return sharedPref.getString(APP_ID_KEY, APPLICATION_ID);
    }

    /**
     * Get the boolean preference whether to stop the cast app on disconnect
     *
     * @param ctx Context
     * @return true if we should stop on disconnect
     */
    public static boolean isDestroyAppOnDisconnect(Context ctx) {
        SharedPreferences sharedPref = PreferenceManager.getDefaultSharedPreferences(ctx);
        return sharedPref.getBoolean(TERM_POLICY_KEY, false);
    }

    /**
     * Get the preferred bit rate from the preferences
     *
     * @param ctx Context
     * @return Return 0 (low), 1 (medium), or 2 (high)
     */
    public static int getPreferredBitRate(Context ctx) {
        SharedPreferences sharedPref = PreferenceManager.getDefaultSharedPreferences(ctx);
        String s = sharedPref.getString(BIT_RATE_KEY, "0");
        return Integer.valueOf(s);
    }

    /**
     * Set up the {@link android.app.ActionBar}, if the API is available.
     */
    private void setupActionBar() {
        getSupportActionBar().setDisplayHomeAsUpEnabled(true);
    }

    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        int id = item.getItemId();
        if (id == android.R.id.home) {
            NavUtils.navigateUpFromSameTask(this);
            return true;
        }
        return super.onOptionsItemSelected(item);
    }

    @Override
    protected void onPostCreate(Bundle savedInstanceState) {
        super.onPostCreate(savedInstanceState);

        setupSimplePreferencesScreen();
        final String av = Utils.getAppVersionName(this);
        final String v = getString(R.string.version, av);
        LOGd(TAG, "Version to set in settings: " + v + " (" + av + ")");
        EditTextPreference versionPref = (EditTextPreference) findPreference("app_version");
        if (versionPref == null) {
            LOGw(TAG, "No app_version preference");
            return;
        }
        versionPref.setTitle(v);
    }

    /**
     * Shows the simplified settings UI if the device configuration if the
     * device configuration dictates that a simplified, single-pane UI should be
     * shown.
     */
    private void setupSimplePreferencesScreen() {
        if (!isSimplePreferences(this)) {
            return;
        }
        LOGd(TAG, "Creating simple layout");

        // Add 'general' preferences.
        addPreferencesFromResource(R.xml.pref_general);

        bindPreferenceSummaryToValue(findPreference(BIT_RATE_KEY));
        bindPreferenceSummaryToValue(findPreference(APP_ID_KEY));
        bindPreferenceSummaryToValue(findPreference(VOL_CTRL_KEY));
        findPreference(TERM_POLICY_KEY).setOnPreferenceChangeListener(mListener);
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public boolean onIsMultiPane() {
        return isXLargeTablet(this) && !isSimplePreferences(this);
    }

    /**
     * Helper method to determine if the device has an extra-large screen. For
     * example, 10" tablets are extra-large.
     */
    private static boolean isXLargeTablet(Context context) {
        return (context.getResources().getConfiguration().screenLayout
                & Configuration.SCREENLAYOUT_SIZE_MASK) >= Configuration.SCREENLAYOUT_SIZE_XLARGE;
    }

    /**
     * Determines whether the simplified settings UI should be shown. This is
     * true if this is forced via {@link #ALWAYS_SIMPLE_PREFS}, or the device
     * doesn't have newer APIs like {@link PreferenceFragment}, or the device
     * doesn't have an extra-large screen. In these cases, a single-pane
     * "simplified" settings UI should be shown.
     */
    private static boolean isSimplePreferences(Context context) {
        return ALWAYS_SIMPLE_PREFS
                || Build.VERSION.SDK_INT < Build.VERSION_CODES.HONEYCOMB
                || !isXLargeTablet(context);
    }

    /**
     * {@inheritDoc}
     */
    @Override
    @TargetApi(Build.VERSION_CODES.HONEYCOMB)
    public void onBuildHeaders(List<Header> target) {
        LOGd(TAG, "Creating headers");
        if (!isSimplePreferences(this)) {
            loadHeadersFromResource(R.xml.pref_headers, target);
        }
    }

    /**
     * A preference listener that will do various specific things
     */
    private static Preference.OnPreferenceChangeListener mListener
            = new Preference.OnPreferenceChangeListener() {
        @Override
        public boolean onPreferenceChange(Preference preference, Object value) {
            final Context ctx = preference.getContext();
            if (TERM_POLICY_KEY.equals(preference.getKey())) {
                Application.getCastManager(ctx).setStopOnDisconnect
                        (isDestroyAppOnDisconnect(ctx));

            }
            else if (VOL_CTRL_KEY.equals(preference.getKey())) {
                String which = value.toString();
                VideoCastManager mgr = Application.getCastManager(ctx);
                mgr.setVolumeType(which.equals("device") ? VideoCastManager
                        .VolumeType.DEVICE : VideoCastManager.VolumeType.STREAM);
            }
            else if (APP_ID_KEY.equals(preference.getKey())) {
                String newValue = value.toString();
                SharedPreferences sp = PreferenceManager.
                        getDefaultSharedPreferences(ctx);

                // Get old value stored by BaseCastManager at initialization time
                String oldValue = sp.getString("application-id", newValue);
                LOGd(TAG, "Old application id: " + oldValue + " new value " +
                        newValue);
                // If the new and old value do not agree, then we restart
                if (!oldValue.equals(newValue)) {
                    LOGw(TAG, "Application ID changed to " + getApplicationId(ctx));


                    new AlertDialog.Builder(ctx).setTitle(R.string.oops)
                            .setMessage(ctx.getString(R.string.new_app_id))
                            .setPositiveButton(R.string.ok, new DialogInterface.OnClickListener() {
                                @Override
                                public void onClick(DialogInterface dialog, int id) {
                                    dialog.cancel();
                                    Application.restartApp(ctx);
                                }
                            })
                            .setIcon(android.R.drawable.ic_dialog_alert)
                            .create()
                            .show();
                }
            }
            return true;
        }
    };
    /**
     * A preference value change listener that updates the preference's summary
     * to reflect its new value.
     */
    private static Preference.OnPreferenceChangeListener mBindListener = new Preference.OnPreferenceChangeListener() {
        @Override
        public boolean onPreferenceChange(Preference preference, Object value) {
            String stringValue = value.toString();
            if (preference instanceof ListPreference) {
                // For list preferences, look up the correct display value in
                // the preference's 'entries' list.
                ListPreference listPreference = (ListPreference) preference;
                int index = listPreference.findIndexOfValue(stringValue);

                // Set the summary to reflect the new value.
                preference.setSummary(
                        index >= 0 ? listPreference.getEntries()[index] : null);

            } else {
                // For all other preferences, set the summary to the value's
                // simple string representation.
                preference.setSummary(stringValue);
            }
            String key = preference.getKey();
            if (key.equals(APP_ID_KEY) || key.equals(VOL_CTRL_KEY))
                mListener.onPreferenceChange(preference, value);
            return true;
        }
    };

    /**
     * Binds a preference's summary to its value. More specifically, when the
     * preference's value is changed, its summary (line of text below the
     * preference title) is updated to reflect the value. The summary is also
     * immediately updated upon calling this method. The exact display format is
     * dependent on the type of preference.
     *
     * @see #mBindListener
     */
    private static void bindPreferenceSummaryToValue(Preference preference) {
        // Set the listener to watch for value changes.
        preference.setOnPreferenceChangeListener(mBindListener);

        // Trigger the listener immediately with the preference's
        // current value.
        LOGd(TAG, "Binding " + preference.getKey());
        SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences
                (preference.getContext());
        if (sp == null) {
            LOGw(TAG, "No shared preferences");
            return;
        }
        String v = "";
        try {
            v = sp.getString(preference.getKey(), "");
        } catch (Exception e) {
            LOGw(TAG, "Failed to get value for " + preference.getKey(), e);
            return;
        }

        mBindListener.onPreferenceChange(preference, v);
    }

    /**
     * This fragment shows general preferences only. It is used when the
     * activity is showing a two-pane settings UI.
     */
    @TargetApi(Build.VERSION_CODES.HONEYCOMB)
    public static class Fragment extends PreferenceFragment {
        @Override
        public void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            addPreferencesFromResource(R.xml.pref_general);
            LOGd(TAG, "Created preference fragment");
            // Bind the summaries of EditText/List/Dialog/Ringtone preferences
            // to their values. When their values change, their summaries are
            // updated to reflect the new value, per the Android Design
            // guidelines.
            bindPreferenceSummaryToValue(findPreference(BIT_RATE_KEY));
            bindPreferenceSummaryToValue(findPreference(APP_ID_KEY));
            bindPreferenceSummaryToValue(findPreference(VOL_CTRL_KEY));
            findPreference(TERM_POLICY_KEY).setOnPreferenceChangeListener(mListener);
        }
    }
}
